{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Transformer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "This tutorial is available as an IPython notebook at [Malaya/example/transformer](https://github.com/huseinzol05/Malaya/tree/master/example/transformer).\n",
    "    \n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ['CUDA_VISIBLE_DEVICES'] = ''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.8/site-packages/bitsandbytes/cextension.py:34: UserWarning: The installed version of bitsandbytes was compiled without GPU support. 8-bit optimizers, 8-bit multiplication, and GPU quantization are unavailable.\n",
      "  warn(\"The installed version of bitsandbytes was compiled without GPU support. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.8/site-packages/bitsandbytes/libbitsandbytes_cpu.so: undefined symbol: cadam32bit_grad_fp32\n",
      "CPU times: user 3.3 s, sys: 3.61 s, total: 6.9 s\n",
      "Wall time: 2.64 s\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/dev/malaya/malaya/tokenizer.py:214: FutureWarning: Possible nested set at position 3397\n",
      "  self.tok = re.compile(r'({})'.format('|'.join(pipeline)))\n",
      "/home/husein/dev/malaya/malaya/tokenizer.py:214: FutureWarning: Possible nested set at position 3927\n",
      "  self.tok = re.compile(r'({})'.format('|'.join(pipeline)))\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "import malaya"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### list Transformer HuggingFace available"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'mesolitica/roberta-base-bahasa-cased': {'Size (MB)': 443},\n",
       " 'mesolitica/roberta-tiny-bahasa-cased': {'Size (MB)': 66.1},\n",
       " 'mesolitica/bert-base-standard-bahasa-cased': {'Size (MB)': 443},\n",
       " 'mesolitica/bert-tiny-standard-bahasa-cased': {'Size (MB)': 66.1},\n",
       " 'mesolitica/roberta-base-standard-bahasa-cased': {'Size (MB)': 443},\n",
       " 'mesolitica/roberta-tiny-standard-bahasa-cased': {'Size (MB)': 66.1},\n",
       " 'mesolitica/electra-base-generator-bahasa-cased': {'Size (MB)': 140},\n",
       " 'mesolitica/electra-small-generator-bahasa-cased': {'Size (MB)': 19.3},\n",
       " 'mesolitica/malaysian-debertav2-base': {'Size (MB)': 228}}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "malaya.transformer.available_huggingface"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "strings = ['Kerajaan galakkan rakyat naik public transport tapi parking kat lrt ada 15. Reserved utk staff rapid je dah berpuluh. Park kereta tepi jalan kang kene saman dgn majlis perbandaran. Kereta pulak senang kene curi. Cctv pun tak ada. Naik grab dah 5-10 ringgit tiap hari. Gampang juga',\n",
    "           'Alaa Tun lek ahhh npe muka masam cmni kn agong kata usaha kerajaan terdahulu sejak selepas merdeka',\n",
    "           \"Orang ramai cakap nurse kerajaan garang. So i tell u this. Most of our local ppl will treat us as hamba abdi and they don't respect us as a nurse\",\n",
    "          'Pemuda mogok lapar desak kerajaan prihatin isu iklim',\n",
    "          'kerajaan perlu kisah isu iklim, pemuda mogok lapar',\n",
    "          'Kerajaan dicadang tubuh jawatankuasa khas tangani isu alam sekitar']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load HuggingFace model\n",
    "\n",
    "```python\n",
    "def huggingface(\n",
    "    model: str = 'mesolitica/electra-base-generator-bahasa-cased',\n",
    "    force_check: bool = True,\n",
    "    **kwargs,\n",
    "):\n",
    "    \"\"\"\n",
    "    Load transformer model.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    model: str, optional (default='mesolitica/electra-base-generator-bahasa-cased')\n",
    "        Check available models at `malaya.transformer.available_transformer()`.\n",
    "    force_check: bool, optional (default=True)\n",
    "        Force check model one of malaya model.\n",
    "        Set to False if you have your own huggingface model.\n",
    "    \"\"\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = malaya.transformer.huggingface(model = 'mesolitica/electra-base-generator-bahasa-cased')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "deberta = malaya.transformer.huggingface(model = 'mesolitica/malaysian-debertav2-base')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I have random sentences copied from Twitter, searched using `kerajaan` keyword."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Vectorization\n",
    "\n",
    "Change a string or batch of strings to latent space / vectors representation.\n",
    "\n",
    "```python\n",
    "def vectorize(\n",
    "    self,\n",
    "    strings: List[str],\n",
    "    method: str = 'last',\n",
    "    method_token: str = 'first',\n",
    "    t5_head_logits: bool = True,\n",
    "    **kwargs,\n",
    "):\n",
    "    \"\"\"\n",
    "    Vectorize string inputs.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    strings: List[str]\n",
    "    method: str, optional (default='last')\n",
    "        hidden layers supported. Allowed values:\n",
    "\n",
    "        * ``'last'`` - last layer.\n",
    "        * ``'first'`` - first layer.\n",
    "        * ``'mean'`` - average all layers.\n",
    "\n",
    "        This only applicable for non T5 models.\n",
    "    method_token: str, optional (default='first')\n",
    "        token layers supported. Allowed values:\n",
    "\n",
    "        * ``'last'`` - last token.\n",
    "        * ``'first'`` - first token.\n",
    "        * ``'mean'`` - average all tokens.\n",
    "\n",
    "        usually pretrained models trained on `first` token for classification task.\n",
    "        This only applicable for non T5 models.\n",
    "    t5_head_logits: str, optional (default=True)\n",
    "        if True, will take head logits, else, last token.\n",
    "        This only applicable for T5 models.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    result: np.array\n",
    "    \"\"\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics.pairwise import cosine_similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "You're using a ElectraTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(6, 256)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v = model.vectorize(strings)\n",
    "v.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.0000001 , 0.72213906, 0.70548326, 0.6682125 , 0.64426583,\n",
       "        0.680184  ],\n",
       "       [0.72213906, 1.        , 0.6226626 , 0.71866846, 0.699285  ,\n",
       "        0.710604  ],\n",
       "       [0.70548326, 0.6226626 , 0.99999994, 0.6309347 , 0.63519984,\n",
       "        0.6296928 ],\n",
       "       [0.6682125 , 0.71866846, 0.6309347 , 0.9999999 , 0.9547027 ,\n",
       "        0.85647124],\n",
       "       [0.64426583, 0.699285  , 0.63519984, 0.9547027 , 1.0000002 ,\n",
       "        0.8234203 ],\n",
       "       [0.680184  , 0.710604  , 0.6296928 , 0.85647124, 0.8234203 ,\n",
       "        1.0000001 ]], dtype=float32)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cosine_similarity(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "You're using a PreTrainedTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(6, 768)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v = deberta.vectorize(strings)\n",
    "v.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.0000004 , 0.9992135 , 0.986294  , 0.97192407, 0.9581215 ,\n",
       "        0.99513686],\n",
       "       [0.9992135 , 0.9999999 , 0.9872771 , 0.97267383, 0.96142304,\n",
       "        0.99459785],\n",
       "       [0.986294  , 0.9872771 , 1.0000001 , 0.99598175, 0.98882604,\n",
       "        0.9702525 ],\n",
       "       [0.97192407, 0.97267383, 0.99598175, 0.9999999 , 0.9930133 ,\n",
       "        0.95082116],\n",
       "       [0.9581215 , 0.96142304, 0.98882604, 0.9930133 , 1.        ,\n",
       "        0.9365195 ],\n",
       "       [0.99513686, 0.99459785, 0.9702525 , 0.95082116, 0.9365195 ,\n",
       "        0.9999993 ]], dtype=float32)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cosine_similarity(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Attention"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "def attention(\n",
    "    self,\n",
    "    strings: List[str],\n",
    "    method: str = 'last',\n",
    "    method_head: str = 'mean',\n",
    "    t5_attention: str = 'cross_attentions',\n",
    "    **kwargs,\n",
    "):\n",
    "    \"\"\"\n",
    "    Get attention string inputs.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    strings: List[str]\n",
    "    method: str, optional (default='last')\n",
    "        Attention layer supported. Allowed values:\n",
    "\n",
    "        * ``'last'`` - attention from last layer.\n",
    "        * ``'first'`` - attention from first layer.\n",
    "        * ``'mean'`` - average attentions from all layers.\n",
    "    method_head: str, optional (default='mean')\n",
    "        attention head layer supported. Allowed values:\n",
    "\n",
    "        * ``'last'`` - attention from last layer.\n",
    "        * ``'first'`` - attention from first layer.\n",
    "        * ``'mean'`` - average attentions from all layers.\n",
    "    t5_attention: str, optional (default='cross_attentions')\n",
    "        attention type for T5 models. Allowed values:\n",
    "\n",
    "        * ``'cross_attentions'`` - cross attention.\n",
    "        * ``'encoder_attentions'`` - encoder attention.\n",
    "        * ``'decoder_attentions'`` - decoder attention.\n",
    "\n",
    "        This only applicable for T5 models.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    result : List[List[Tuple[str, float]]]\n",
    "    \"\"\"\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can give list of strings or a string to get the attention, in this documentation, I just want to use a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('Alaa', 0.058868624),\n",
       "  ('Tun', 0.061252587),\n",
       "  ('lek', 0.06898942),\n",
       "  ('ahhh', 0.06439799),\n",
       "  ('npe', 0.05082519),\n",
       "  ('muka', 0.07244483),\n",
       "  ('masam', 0.053202268),\n",
       "  ('cmni', 0.048232798),\n",
       "  ('kn', 0.05816199),\n",
       "  ('agong', 0.06559847),\n",
       "  ('kata', 0.055140313),\n",
       "  ('usaha', 0.057437424),\n",
       "  ('kerajaan', 0.041059937),\n",
       "  ('terdahulu', 0.044371374),\n",
       "  ('sejak', 0.069254234),\n",
       "  ('selepas', 0.06948459),\n",
       "  ('merdeka', 0.061277922)]]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.attention([strings[1]], method = 'last')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('Alaa', 0.061838076),\n",
       "  ('Tun', 0.053071998),\n",
       "  ('lek', 0.04778199),\n",
       "  ('ahhh', 0.046944533),\n",
       "  ('npe', 0.052150372),\n",
       "  ('muka', 0.05392791),\n",
       "  ('masam', 0.058074415),\n",
       "  ('cmni', 0.08068735),\n",
       "  ('kn', 0.050343554),\n",
       "  ('agong', 0.054398913),\n",
       "  ('kata', 0.057019),\n",
       "  ('usaha', 0.05820992),\n",
       "  ('kerajaan', 0.06937862),\n",
       "  ('terdahulu', 0.08067024),\n",
       "  ('sejak', 0.05798509),\n",
       "  ('selepas', 0.06437356),\n",
       "  ('merdeka', 0.053144373)]]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.attention([strings[1]], method = 'first')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('Alaa', 0.048754193),\n",
       "  ('Tun', 0.054038025),\n",
       "  ('lek', 0.053129513),\n",
       "  ('ahhh', 0.057060346),\n",
       "  ('npe', 0.04947073),\n",
       "  ('muka', 0.060973264),\n",
       "  ('masam', 0.05763235),\n",
       "  ('cmni', 0.0723617),\n",
       "  ('kn', 0.05290027),\n",
       "  ('agong', 0.053802904),\n",
       "  ('kata', 0.0701514),\n",
       "  ('usaha', 0.06137535),\n",
       "  ('kerajaan', 0.06380818),\n",
       "  ('terdahulu', 0.06389959),\n",
       "  ('sejak', 0.05665373),\n",
       "  ('selepas', 0.052445903),\n",
       "  ('merdeka', 0.07154253)]]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.attention([strings[1]], method = 'mean')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('Alaa', 0.053318705),\n",
       "  ('Tun', 0.059914347),\n",
       "  ('lek', 0.060762215),\n",
       "  ('ahhh', 0.06112733),\n",
       "  ('npe', 0.06244664),\n",
       "  ('muka', 0.06293835),\n",
       "  ('masam', 0.06351074),\n",
       "  ('cmni', 0.062215753),\n",
       "  ('kn', 0.062704325),\n",
       "  ('agong', 0.06305968),\n",
       "  ('kata', 0.06383533),\n",
       "  ('usaha', 0.06210411),\n",
       "  ('kerajaan', 0.05999032),\n",
       "  ('terdahulu', 0.057203274),\n",
       "  ('sejak', 0.055250105),\n",
       "  ('selepas', 0.052908983),\n",
       "  ('merdeka', 0.036709864)]]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "deberta.attention([strings[1]], method = 'last')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "roberta = malaya.transformer.huggingface(model = 'mesolitica/roberta-base-standard-bahasa-cased')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('Alaa', 0.052424457),\n",
       "  ('Tun', 0.08523697),\n",
       "  ('lek', 0.06813958),\n",
       "  ('ahhh', 0.06153968),\n",
       "  ('npe', 0.06513652),\n",
       "  ('muka', 0.059199475),\n",
       "  ('masam', 0.061626367),\n",
       "  ('cmni', 0.06737201),\n",
       "  ('kn', 0.06622732),\n",
       "  ('agong', 0.052743737),\n",
       "  ('kata', 0.067238666),\n",
       "  ('usaha', 0.044102512),\n",
       "  ('kerajaan', 0.060376044),\n",
       "  ('terdahulu', 0.04183174),\n",
       "  ('sejak', 0.04189242),\n",
       "  ('selepas', 0.039302666),\n",
       "  ('merdeka', 0.065609865)]]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "roberta.attention([strings[1]], method = 'last')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
